home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickTime / Programming Stuff / Documentation / develop articles / develop Issue 12 / Time Bases / TimeBaseSlave / TimeBaseSlave.p < prev    next >
Encoding:
Text File  |  1997-02-26  |  9.8 KB  |  362 lines  |  [TEXT/MPS ]

  1. { }
  2.  
  3. PROGRAM TimeBaseSlave;
  4. Shows how to enslave time bases
  5. and also how to create and use time base call back routines.
  6. }
  7.  
  8. USES
  9.     MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf, Traps, GestaltEqu, 
  10.     Movies, QuickTimeComponents,FixMath;
  11.  
  12. LABEL 123;
  13.  
  14. CONST    MoviePieces = 4;    (* number of movie pieces *)
  15.         kMinDuration = 25;    (* minimun movie duration *)
  16.  
  17. VAR        gMCPlay:        MovieController;
  18.         gWind:            WindowPtr;
  19.         wRect:            Rect;
  20.         gMoov:            Array [1..4] OF Movie;
  21.         gSystemVersion:    Integer;
  22.         gForwardFlag,    
  23.         gDoneFlag:        Boolean;
  24.         gErr:            OSErr;
  25.         gResult,
  26.         enslaving:        Boolean;
  27.         gEventRec:        EventRecord;
  28.         reply:            StandardFileReply;
  29.         doneSizing:        Boolean;
  30.         i, stage:        Integer;
  31.         
  32. {$I TimeBaseSlaveAux.p} { Includes all auxiliary routines. }
  33.  
  34. FUNCTION GetMovie: OSErr;
  35.  
  36.     purpose         get a movie from the selected file. 
  37.                     extend the movie duration is needed.
  38.                     make copies of the movie to have movies to enslave.
  39.                     NOTE: CopyMovieSelection creates an inactive movie; to make it
  40.                           play you have to make it active.
  41. }
  42.  
  43. VAR        where:            Point;
  44.         err:            OSErr;
  45.         movieResFile, 
  46.         resID, i:         Integer;
  47.         wasChanged:        Boolean;
  48.         moovResName:    Str255;
  49.         moovDuration: TimeValue;
  50.         
  51. BEGIN
  52.     err := fnfErr;            { This is as good an error as any other }
  53.  
  54.     err := OpenMovieFile(reply.sfFile, movieResFile, fsRdPerm);
  55.     IF  err = noErr THEN        
  56.       resID := 0;            { First 'moov' found }
  57.       err := NewMovieFromFile( gMoov[1], movieResFile, resID, moovResName, newMovieActive, wasChanged);
  58.       IF CloseMovieFile(movieResFile) <> noErr THEN
  59.         ErrorControl('Could not close the file');
  60.  
  61.     ExtendMovie(gMoov[1]); (* make sure movie is long enough *)
  62.  
  63.     moovDuration := GetMovieDuration(gMoov[1]);
  64.     SetMovieSelection(gMoov[1], 0, moovDuration); (* select whole movie *)
  65.  
  66.     FOR i := 2 TO MoviePieces DO
  67.       BEGIN
  68.         gMoov[i] := CopyMovieSelection(gMoov[1]); (* clone the movie *)
  69.           err := GetMoviesError;
  70.           IF err <> noErr THEN ErrorControl('SetMovieBox failed');
  71.         SetMovieActive(gMoov[i], TRUE);
  72.       END;
  73.     
  74.     GetMovie := err;
  75. END;
  76.  
  77. FUNCTION SetUpMovie(moov: Movie; wind: WindowPtr): OSErr;
  78.  
  79.     purpose         given a window, a movie this routine sizes the
  80.                     window to fit the movie.
  81. }
  82.  
  83. VAR
  84.         err:             OSErr;
  85.         moovBox,
  86.         cBox:     Rect;
  87.         m: Movie;
  88.         
  89. BEGIN
  90.  
  91.     { The movie box may come with negative coordinates so we reset the
  92.       origin to 0,0 }
  93.     GetMovieBox(moov,moovBox); 
  94.     OffsetRect(moovBox, -moovBox.left, -moovBox.top); 
  95.     SetMovieBox(moov, moovBox);
  96.     err := GetMoviesError;
  97.     IF err <> noErr THEN ErrorControl('SetMovieBox failed');
  98.     
  99.     IF NOT doneSizing THEN { We want to resize the window just once }
  100.       BEGIN
  101.         { Resize window to the dimensions of the movie }
  102.         SizeWindow(wind, moovBox.right-moovBox.left,moovBox.bottom-moovBox.top,true);
  103.         ShowWindow(wind);
  104.         doneSizing := TRUE;
  105.       END;
  106.       
  107.     { Tell the movie toolbox where to display the movie,
  108.       also we want to start from the begining
  109.       and set the movie in motion.
  110.     }
  111.     
  112.     SplitMovie(moov, i);
  113.     
  114.     SetMovieGWorld(moov, CGrafPtr(wind), NIL);
  115.         err := GetMoviesError;
  116.         IF err <> noErr THEN ErrorControl('SetMovieGWorld failed');
  117.  
  118.     IF ((i = 1) OR (NOT enslaving)) THEN     { we do this only for the first movie if     }
  119.       BEGIN                                    { time bases are being enslaved                }
  120.         GotoBeginningOfMovie(moov);
  121.             err := GetMoviesError;
  122.             IF err <> noErr THEN ErrorControl('GotoBeginningOfMovie failed');
  123. (*             
  124.         StartMovie(moov);
  125.             err := GetMoviesError;
  126.             IF err <> noErr THEN ErrorControl('StartMovie failed'); *)
  127.       END;
  128.     SetUpMovie := err;
  129. END;
  130.  
  131. PROCEDURE KillMovieSoundTracks(moov: Movie);
  132. VAR    trackCount,
  133.         counter:     Integer;
  134.         atrack:        Track;
  135.         creator:        Str255;
  136.         mediaType,
  137.         manuf:        OSType;
  138.         err:        OSErr;
  139.         
  140. BEGIN
  141.     trackCount := GetMovieTrackCount(moov);
  142.     
  143.     FOR counter := 1 to trackCount DO
  144.       BEGIN
  145.         aTrack := GetMovieIndTrack(moov, counter);
  146.         GetMediaHandlerDescription(GetTrackMedia(aTrack), mediaType, creator, manuf);
  147.         err := GetMoviesError;
  148.         IF err <> noErr THEN
  149.                DebugStr('Error at GetMediaHandlerDescription');
  150.          IF mediaType = 'soun' THEN
  151.            BEGIN
  152.              DisposeMovieTrack(aTrack);
  153.              err := GetMoviesError;
  154.              IF err <> noErr THEN
  155.                DebugStr('Error at disposing tracks');
  156.            END;
  157.       END
  158. END;
  159.  
  160. (* The routine called when the call back event occurs.
  161.    refCon contains the time that triggered the event.
  162.    Note that the A5 world is set up by the movie toolbox
  163.    so globals and such are readily available.
  164. *)
  165. PROCEDURE FlipPieces(cb: QTCallBack; refCon: LONGINT);
  166. VAR    j:     Integer;
  167.         callWhen:            LONGINT;
  168.         scale:            TimeScale;
  169.         stop:            LONGINT;
  170.         tr:                TimeRecord;
  171.         tb:                TimeBase;
  172.         err:            OSErr;
  173. BEGIN
  174.  
  175.     stage := (stage + 1) MOD 4;
  176.  
  177.     FOR j:= 1 TO MoviePieces DO
  178.       BEGIN
  179.         ShiftMoviePieces(j);
  180.       END;
  181.     (* Time to reprime the callback. We want to be called in
  182.        three seconds, unless that would put us after the end of the movie.*)
  183.     tb := GetCallBackTimeBase(cb);
  184.     scale := 600;                (* 100 units in this scale mean one second     *)
  185.     callWhen := refCon + (3*scale);        (* call me in 3 seconds                *)
  186.     stop := GetTimeBaseStopTime(tb, scale, tr);
  187.     IF callWhen > stop THEN (* wrap around the three seconds *)
  188.       callWhen := GetTimeBaseStartTime(tb, scale, tr) + callWhen - stop; 
  189.       
  190. {        callWhen := GetTimeBaseStartTime(tb, scale, tr);
  191. }
  192.     err := CallMeWhen(cb, @FlipPieces, callWhen, triggerTimeFwd+callBackAtInterrupt, callWhen, scale);
  193. {    err := CallMeWhen(cb, @FlipPieces, when, triggerTimeFwd, when, scale);
  194. }
  195. END;
  196.  
  197. (* Here we create a TimeBase call back that will allow us to flip
  198.    the movies at regular intervals.
  199. *)
  200. FUNCTION SetCallBack: OSerr;
  201.  
  202. VAR     err :             OSErr;
  203.         cb:                QTCallBack;
  204.         tb:                TimeBase;
  205.         when:            LONGINT;
  206.         scale:            TimeScale;
  207.         
  208. BEGIN
  209.     tb := GetMovieTimeBase(gMoov[1]);    { get time base    of first movie            }
  210.         err := GetMoviesError;
  211.         IF err <> noErr THEN ErrorControl('GetMovieTimeBase failed');
  212.     (* want to be called at regular intervals so we use the callBackAtTime type;
  213.        note that if the high bit is set then the call back occurs at interrupt time,
  214.        this is not necessary here.
  215.     *)
  216.     cb := NewCallBack(tb,  callBackAtTime);
  217.     
  218.     (* CallMeWhen primes the task and sets the routine that has to be called *)
  219.     scale := 100;    (* 100 units in this scale mean one second     *)
  220.     when := 3 * scale;        (* call me in 3 seconds                        *)
  221.  
  222.     err := CallMeWhen(cb, @FlipPieces, when, triggerTimeFwd, when, scale);
  223.     IF err <> noErr THEN
  224.       DebugStr('CallMeWhen failed');
  225. END;
  226.  
  227. FUNCTION EnslaveMovies: OSerr;
  228.  
  229. VAR        err:             OSErr;
  230.         masterTimeBase:    TimeBase;
  231.         slaveZero:        TimeRecord;
  232.         slaveZeroTV:    TimeValue;
  233.         masterScale:    TimeScale;
  234.         count:            Integer;
  235. BEGIN
  236.     IF NOT enslaving THEN EXIT(EnslaveMovies); { nothing to do here }
  237.  
  238.     err := noErr;
  239.     
  240.     masterTimeBase := GetMovieTimeBase(gMoov[1]);    { get time base    of first movie            }
  241.         err := GetMoviesError;
  242.         IF err <> noErr THEN ErrorControl('GetMovieTimeBase failed');
  243.  
  244.     masterScale := GetMovieTimeScale(gMoov[1]);        { needed for SetMovieMasterTimeBase    }
  245.         err := GetMoviesError;
  246.         IF err <> noErr THEN ErrorControl('GetMovieTimeScale failed');
  247.  
  248.     slaveZeroTV := GetTimeBaseStartTime(masterTimeBase, masterScale, slaveZero); { ditto    }
  249.         err := GetMoviesError;
  250.         IF err <> noErr THEN ErrorControl('GetMovieTimeScale failed');
  251.     FOR count := 2 TO 4 DO
  252.       BEGIN
  253.         SetMovieMasterTimeBase(gMoov[count], masterTimeBase, slaveZero); { now we do it                }
  254.             err := GetMoviesError;
  255.             IF err <> noErr THEN 
  256.               BEGIN
  257.                 ErrorControl('SetMovieMasterTimeBase failed');
  258.                 LEAVE;
  259.               END;
  260.         { Since we are here we'll shut up all slave movies, there is only one sound anyway }
  261.         KillMovieSoundTracks(gMoov[count]);
  262.       END;
  263.       
  264.     EnslaveMovies := err;
  265. END;
  266.  
  267. PROCEDURE DoUpdate(theEvent : EventRecord);
  268.     purpose         responds to update events
  269. }
  270. BEGIN
  271.     BeginUpdate(WindowPtr(theEvent.message));
  272.     SetPort(WindowPtr(theEvent.message));
  273.  
  274.     IF UpdateMovie(gMoov[1]) <> noErr THEN
  275.       ErrorControl('UpdateMovie failed');
  276.  
  277.     EndUpdate(WindowPtr(theEvent.message));
  278. END; (* DoUpdate *)
  279.  
  280. BEGIN (* QTSample *)
  281.  
  282.     IF InitSystem <> noErr THEN            { Initialize all managers             }
  283.       BEGIN
  284.         ErrorControl('Initialization failed');
  285.         Exit(PROGRAM);
  286.       END;
  287.       
  288.     gWind := NewCWindow(NIL, wRect, 'TimeBaseSlave Window', false, noGrowDocProc, 
  289.                         WindowPtr(-1), true, 0);
  290.                         
  291.     SetPort(gWind);            { Make our window the current port    }
  292.  
  293. 123:InitVars;
  294.     IF DisplayGetFile('Please select movie file:',reply) THEN{ ask user to select a movie file     }
  295.       BEGIN
  296.         gErr := GetMovie; (* get movie and replicate it *)
  297.       END
  298.     ELSE
  299.       gErr := fnfErr;
  300.       
  301.     IF gErr <> noErr THEN    
  302.       ErrorControl('Could not get the movie, Bye!;g')
  303.     ELSE            { if we have a movie then continue     }
  304.       BEGIN
  305.         FOR i:= 1 TO MoviePieces DO
  306.           BEGIN
  307.             gErr := SetUpMovie(gMoov[i],gWind);
  308.             IF gErr <> noErr THEN LEAVE;
  309.           END;
  310.         
  311.         gErr := EnslaveMovies;
  312.         
  313.         gErr := SetCallBack;
  314.         
  315.         StartMovie(gMoov[1]);
  316.           gErr := GetMoviesError;
  317.           IF gErr <> noErr THEN ErrorControl('StartMovie failed'); 
  318.  
  319.         IF gErr <> noErr THEN 
  320.           ErrorControl('Error at SetUpMovie')
  321.         ELSE
  322.           BEGIN
  323.             WHILE NOT gDoneFlag DO
  324.               BEGIN
  325.                 gResult := GetNextEvent(everyEvent, gEventRec);
  326.                 IF gResult  THEN    
  327.                   HandleEvent(gEventRec)             { Cliks in go away terminate movie             }
  328.                 ELSE
  329.                   BEGIN
  330.                     FOR i := 1 TO MoviePieces DO
  331.                       MoviesTask(gMoov[i], doTHeRIghtThing); (* doTHeRIghtThing) *)
  332.                     IF IsMovieDone(gMoov[1]) THEN    
  333.                       BEGIN
  334.                         { if using slaves then moving the master to the
  335.                           begining moves the others also
  336.                         }
  337.                         SysBeep(1);
  338.                         IF enslaving THEN
  339.                           GoToBeginningOfMovie(gMoov[1])
  340.                         ELSE
  341.                           BEGIN
  342.                           { if not all have to be done one by one }
  343.                             DebugStr('we are not enslaving');
  344.                             FOR i:= 1 TO MoviePieces DO
  345.                               GoToBeginningOfMovie(gMoov[i]);
  346.                           END
  347.                       END;
  348.                   END
  349.               END
  350.           END;
  351.         { NEVER, EVER dispose the master movie first!!!! }
  352.         FOR i:=MoviePieces DOWNTO 1 DO
  353.           DisposeMovie(gMoov[i]);
  354.         GOTO 123;
  355.       END;
  356.     DisposeWindow(gWind);
  357.     ExitMovies;
  358. END.